/*******************************************************************************
	RDMA client module
*******************************************************************************/
#include "main.h"

uint32_t cltBufPos = 0;
uint32_t bytesBufLeft = 2097152;
uint32_t totalRDMASent = 0;

static byte cltBuffer[2097152];

RDMAClientModule::RDMAClientModule(int port)
{
	rdmaUtil = new RDMAUtil(EP_CLIENT, port);
}

bool RDMAClientModule::process(vector<Instruction *> *list)
{
	uint32_t num = list->size();
	
	if (!internalWrite(&num, sizeof(uint32_t)))
		return false;

	for (int n=0; n<(int)list->size(); n++) {
		Instruction *i = (*list)[n];
		
		//Check for NULL buffers and reset length if necessary
		for (int n=0;n<3;n++) {
			int l = i->buffers[n].len;
			if(l > 0 && !i->buffers[n].buffer) {
				i->buffers[n].len = 0;
			}
		}
		
		//now the struct itself	
		if(internalWrite(i, sizeof(Instruction)) != sizeof(Instruction))
			return false;

		//Now see if we need to send any buffers
		for (int n=0; n<3; n++) {
			int l = i->buffers[n].len;
			if (l > 0) {
				if (internalWrite(i->buffers[n].buffer, l) != l)
					return false;

				//And check if we're expecting a buffer back in response
				if (i->buffers[n].needReply) {
					sendBuffer();

					if (i->id==256)
				    	l = 5;

					int x = internalRead(i->buffers[n].buffer, l);
					if (x < 0)
						return false;
				}
			}
		}
	}
	
	sendBuffer();
	Stats::count("mod_rdmaclient send", totalRDMASent);
	totalRDMASent = 0;

	return true;
}

bool RDMAClientModule::sync()
{
	return true;
}

int RDMAClientModule::internalWrite(void* buf, int nByte)
{   		
	if (bytesBufLeft - nByte > 0) {
		memcpy(cltBuffer + cltBufPos, buf, nByte);

		cltBufPos += nByte;
		bytesBufLeft -= nByte;
	} else {
		sendBuffer();
	}
	return nByte;
}

void RDMAClientModule::sendBuffer()
{
	static int count=0;
	int ret = 0;
	uint32_t dummy = 0;
	if (cltBufPos == 0)
		return;

	if (gConfig->networkCompression) {
		cltBufPos = Compression::compress(cltBuffer, cltBufPos);
		ret = rdmaUtil->send2(Compression::getBuf(), cltBufPos);
	} else {
		ret = rdmaUtil->send2(cltBuffer, cltBufPos);
	}

	if (ret < 0) {
		LOG("Failed to send buffer\n");
		return;
	}

	totalRDMASent += cltBufPos;
	cltBufPos = 0;
	bytesBufLeft = 2097152;
	if (count!=-1) count++;
}

int RDMAClientModule::internalRead(void *buf, size_t count)
{
	int	ret = rdmaUtil->recv2(cltBuffer);
	if (ret < 0) return ret;

	memcpy(buf, cltBuffer, count);

	return count;
}

int RDMAClientModule::readFrame(byte *frame)
{
	int ret = rdmaUtil->recv2(frame);
	if (ret < 0)
		LOG("Failed to receive frame from server\n");

	return ret;
}